#pragma once
#include "Core\Item.h"
#include <cstdlib>
#include <iostream>
#include "Cardinal.h"
#include "Component\Physics\Transform.h"
#include "Tools\Ref.h"
#include "Tools\Serialization.h"
namespace SakuraAge {

SakuraObject::SakuraObject() {}
SakuraObject::~SakuraObject() {
  for (ObjRef<SakuraObject>* i : refs) {
    i->obj = nullptr;
  }
}

void SakuraObject::Serialize(SerializedStream& ss) {}

std::vector<ObjRef<Item>> ItemFactor::list;
Item::Item() { transform = nullptr; }

Item::~Item() {}

void Item::property__set_active(const property__tmp_type_active& value) {
  if (isActive) {
    forEach([](Item* i) mutable -> void {
      for (ObjRef<Component> comp : i->components) {
        comp->OnEnable();
      }
    });
  } else {
    forEach([](Item* i) mutable -> void {
      for (ObjRef<Component> comp : i->components) {
        comp->OnDisable();
      }
    });
  }
}

/**
 * Execute func in all child.
 *
 * @param func the execute function or lambda
 * @param checkActive whether execute on disable object
 */
void Item::forEach(std::function<void(Item*)> func, bool checkActive) {
  if (!(checkActive || isActive)) return;
  func(this);
  if (!this->transform->children.empty()) {
    for (ObjRef<Transform> child : this->transform->children) {
      child->item->forEach(func, checkActive);
    }
  }
}
/**
 * Execute func in all child.The 
 * funciton end when it return false.
 *
 * @param func the execute function or lambda. 
 * @param checkActive whether execute on disable object
 */
bool Item::forEach(std::function<bool(Item*)> func, bool checkActive) {
  if (!(checkActive || isActive)) return false;
  if (func(this)) return true;
  if (!this->transform->children.empty()) {
    for (ObjRef<Transform> child : this->transform->children) {
      if (child->item->forEach(func, checkActive)) {
        return true;
      }
    }
  }
  return false;
}

void Item::Serialize(SerializedStream& ss) {
  ss& name;
  ss& isActive;
  ss&(ObjectRef&)transform;
  ss&& components;
}
/**
 * Create an item and add it into scene.
 * 
 * @param void
 */
Item* SakuraAge::ItemFactor::CreateItem() {
  Item* i = new Item();
  list.push_back(i);
  i->transform = Component::Add<Transform>(i);
  i->transform->father =
      Cardinal::scenes[Cardinal::activeScene]->Father->transform;
  return i;
}
Item* ItemFactor::CreateItem(const std::string& name) {
  Item* i = new Item();
  list.push_back(i);
  i->transform = Component::Add<Transform>(i);
  i->name = name;
  return i;
}

Component::~Component() { this->OnDestory(); }
Component::Component() {}

void Component::Awake() {}
void Component::OnDestory() {}
void Component::Update() {}

void Component::OnEnable() {}

void Component::OnDisable() {}


void Component::Serialize(SerializedStream& ss) {
  // this->SakuraObject::Serialize(ss);
  ss&(ObjectRef&)item;
  ss& Active;
}
}  // namespace SakuraAge
